﻿using System;
using System.Text;
using AbstractProducts;
using SmartAssembly;

namespace AbstractBugTracker
{
    public class BugRef : IEquatable<BugRef>
    {
        private readonly ProductRef m_ProductRef;
        private readonly string m_MethodTypeName;
        private readonly string m_MethodName;
        private readonly string m_ExceptionTypeName;
        private readonly string m_ExceptionReportHash;

        public BugRef(ProcessedReport processedReport, IExceptionReportHasher exceptionReportHasher, IExceptionReportMapper exceptionReportMapper)
            : this(processedReport.ProductBuildRef.ProductRef,
                    exceptionReportMapper.MapMethodTypeName(BugRefUtils.MapMethodTypeName(processedReport.Report.MethodTypeName)),
                    BugRefUtils.MapMethodName(processedReport.Report.MethodName),
                    exceptionReportMapper.MapExceptionTypeName(processedReport.Report.ExceptionTypeName),
                    exceptionReportHasher.GetExceptionReportHash(processedReport.Report)
                    )
        {
        }

        protected BugRef(ProductRef productRef, string methodTypeName, string methodName, string exceptionTypeName, string exceptionReportHash)
        {
            if (productRef == null) throw new ArgumentNullException("productRef");
            if (methodTypeName == null) throw new ArgumentNullException("methodTypeName");
            if (methodName == null) throw new ArgumentNullException("methodName");
            if (exceptionTypeName == null) throw new ArgumentNullException("exceptionTypeName");
            m_ProductRef = productRef;
            m_MethodTypeName = methodTypeName;
            m_MethodName = methodName;
            m_ExceptionTypeName = exceptionTypeName;
            m_ExceptionReportHash = exceptionReportHash;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("ProductRef: {0}", m_ProductRef);
            sb.AppendLine();
            sb.AppendFormat("MethodTypeName: {0}", m_MethodTypeName);
            sb.AppendLine();
            sb.AppendFormat("MethodName: {0}", m_MethodName);
            sb.AppendLine();
            sb.AppendFormat("ExceptionTypeName: {0}", m_ExceptionTypeName);
            sb.AppendLine();
            sb.AppendFormat("ExceptionReportHash: {0}", m_ExceptionReportHash);
            return sb.ToString();
        }

        public ProductRef ProductRef
        {
            get { return m_ProductRef; }
        }

        public string MethodTypeName
        {
            get { return m_MethodTypeName; }
        }

        public string MethodName
        {
            get { return m_MethodName; }
        }

        public string ExceptionTypeName
        {
            get { return m_ExceptionTypeName; }
        }

        public string ExceptionReportHash
        {
            get { return m_ExceptionReportHash; }
        }

        public bool Equals(BugRef other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return Equals(other.m_ProductRef, m_ProductRef) && Equals(other.m_MethodTypeName, m_MethodTypeName) && Equals(other.m_MethodName, m_MethodName) && Equals(other.m_ExceptionTypeName, m_ExceptionTypeName) && Equals(other.m_ExceptionReportHash, m_ExceptionReportHash);
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as BugRef);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                int result = m_ProductRef.GetHashCode();
                result = (result*397) ^ m_MethodTypeName.GetHashCode();
                result = (result*397) ^ m_MethodName.GetHashCode();
                result = (result*397) ^ m_ExceptionTypeName.GetHashCode();
                result = (result*397) ^ (m_ExceptionReportHash != null ? m_ExceptionReportHash.GetHashCode() : 0);
                return result;
            }
        }

        public static bool operator ==(BugRef left, BugRef right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(BugRef left, BugRef right)
        {
            return !Equals(left, right);
        }
    }
}
